#region Using directives

/*
 * Copyright (c) 2007 Alan Dean.
 * All rights released.
 */

using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Security.Permissions;

using Edenbrook;
using Edenbrook.Globalization;

#endregion

namespace Edenbrook.Telephony
{
    #region Overview
    /// <summary>
    /// Represents the location of a character.
    /// <para>This class cannot be inherited.</para>
    /// </summary>
    /// 
    /// <remarks>
    /// The location is defined by button placement and position on the button.
    /// </remarks>
    #endregion
    public struct CharacterLocation : IComparable
    {
        // public constructors

        #region public CharacterLocation(int, int)
        /// <overloads>
        /// Initializes a new instance of the <see cref="T:Edenbrook.Telephony.CharacterLocation"/> class.
        /// </overloads>
        /// 
        /// <summary>
        /// Initializes a new instance of the <see cref="T:Edenbrook.Telephony.CharacterLocation"/> class
        /// with the specified <paramref name="button"/> and <paramref name="position"/>.
        /// </summary>
        /// 
        /// <param name="button">The button hosting the character.</param>
        /// <param name="position">The position of the character on the button.</param>
        /// 
        /// <remarks>None</remarks>
        public CharacterLocation(int button, int position)
        {
            if ((button < 0) || (button > 9)) throw ExceptionFactory.ButtonNumber("button", button);

            _button = button;
            _position = position;
        }
        #endregion

        // public static operators

        #region public static implicit operator string(CharacterLocation)
        /// <summary>
        /// Implicitly casts the <paramref name="value"/> to a <see langword="string"/>.
        /// </summary>
        /// 
        /// <param name="value">The <see cref="T:Edenbrook.Telephony.CharacterLocation"/> to be cast.</param>
        /// 
        /// <returns>A <see langword="string"/>.</returns>
        /// 
        /// <remarks>None</remarks>
        public static implicit operator string(CharacterLocation value)
        {
            return value.ToString();
        }
        #endregion

        #region public static bool operator ==
        /// <summary>
        /// Implements the equality operator for the <see cref="T:Edenbrook.Telephony.CharacterLocation"/> class.
        /// </summary>
        /// 
        /// <param name="expr1">The left operand.</param>
        /// <param name="expr2">The right operand.</param>
        /// 
        /// <returns>
        /// <see langword="true"/> if the values of its operands are equal;
        /// otherwise, <see langword="false"/>.
        /// </returns>
        /// 
        /// <remarks>The equality operator is strongly-typed.</remarks>
        public static bool operator ==(CharacterLocation expr1, CharacterLocation expr2)
        {
            return expr1.Equals(expr2);
        }
        #endregion

        #region public static bool operator !=
        /// <summary>
        /// Implements the inequality operator for the <see cref="T:Edenbrook.Telephony.CharacterLocation"/> class.
        /// </summary>
        /// 
        /// <param name="expr1">The left operand.</param>
        /// <param name="expr2">The right operand.</param>
        /// 
        /// <returns>
        /// <see langword="true"/> if the values of its operands are not equal;
        /// otherwise, <see langword="false"/>.
        /// </returns>
        /// 
        /// <remarks>The inequality operator is strongly-typed.</remarks>
        public static bool operator !=(CharacterLocation expr1, CharacterLocation expr2)
        {
            return !(expr1.Equals(expr2));
        }
        #endregion

        #region public static bool operator <
        /// <summary>
        /// Implements the less than operator for the <see cref="T:Edenbrook.Telephony.CharacterLocation"/> class.
        /// </summary>
        /// 
        /// <param name="expr1">The left operand.</param>
        /// <param name="expr2">The right operand.</param>
        /// 
        /// <returns>
        /// <see langword="true"/> if the first operands is less than the second operand;
        /// otherwise, <see langword="false"/>.
        /// </returns>
        /// 
        /// <remarks>The operator is strongly-typed.</remarks>
        public static bool operator <(CharacterLocation expr1, CharacterLocation expr2)
        {
            return (CharacterLocation.Compare(expr1, expr2) < 0);
        }
        #endregion

        #region public static bool operator >
        /// <summary>
        /// Implements the greater than operator for the <see cref="T:Edenbrook.Telephony.CharacterLocation"/> class.
        /// </summary>
        /// 
        /// <param name="expr1">The left operand.</param>
        /// <param name="expr2">The right operand.</param>
        /// 
        /// <returns>
        /// <see langword="true"/> if the first operands is greater than the second operand;
        /// otherwise, <see langword="false"/>.
        /// </returns>
        /// 
        /// <remarks>The operator is strongly-typed.</remarks>
        public static bool operator >(CharacterLocation expr1, CharacterLocation expr2)
        {
            return (CharacterLocation.Compare(expr1, expr2) > 0);
        }
        #endregion

        // public static methods

        #region public static int Compare(CharacterLocation, CharacterLocation)
        /// <summary>
        /// Compares two expressions and returns an indication of their relative values.
        /// </summary>
        /// 
        /// <param name="expr1">An <see cref="T:Edenbrook.Telephony.CharacterLocation"/>.</param>
        /// <param name="expr2">An <see cref="T:Edenbrook.Telephony.CharacterLocation"/>.</param>
        /// 
        /// <returns>A signed number indicating the relative values of the two expressions.</returns>
        /// 
        /// <remarks>None</remarks>
        public static int Compare(CharacterLocation expr1, CharacterLocation expr2)
        {
            return String.Compare(expr1.ToString(), expr2.ToString(), StringComparison.OrdinalIgnoreCase);
        }
        #endregion

        // public properties

        #region public int Button
        /// <summary>
        /// Gets the button hosting the character.
        /// </summary>
        /// 
        /// <value>
        /// The button hosting the character.
        /// </value>
        /// 
        /// <remarks>None</remarks>
        public int Button
        {
            get
            {
                return _button;
            }
        }

        /// <summary>
        /// Stores the <see cref="P:Edenbrook.Telephony.CharacterLocation.Button"/> data.
        /// </summary>
        /// 
        /// <remarks>None</remarks>
        private int _button;
        #endregion

        #region public int Position
        /// <summary>
        /// Gets the position of the character on the button.
        /// </summary>
        /// 
        /// <value>
        /// The position of the character on the button.
        /// </value>
        /// 
        /// <remarks>None</remarks>
        public int Position
        {
            get
            {
                return _position;
            }
        }

        /// <summary>
        /// Stores the <see cref="P:Edenbrook.Telephony.CharacterLocation.Position"/> data.
        /// </summary>
        /// 
        /// <remarks>None</remarks>
        private int _position;
        #endregion

        // public methods (IComparable)

        #region public int CompareTo(object)
        /// <summary>Compares the current instance with another object of the same type.</summary>
        /// 
        /// <param name="obj">An object to compare with this instance.</param>
        /// 
        /// <returns>A 32-bit signed integer that indicates the relative order of the objects being compared.</returns>
        /// 
        /// <remarks>None</remarks>
        [SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
        public int CompareTo(object obj)
        {
            int comparison = 1;

            if (!Object.Equals(obj, null))
            {
                if (obj.GetType() != typeof(CharacterLocation))
                {
                    throw ExceptionFactory.ObjectMustBeOfType("obj", typeof(CharacterLocation));
                }
                else
                {
                    comparison = CharacterLocation.Compare(this, (CharacterLocation)obj);
                }
            }

            return comparison;
        }
        #endregion

        // public methods (Object)

        #region public override bool Equals(object)
        /// <summary>
        /// Determines whether the specified <paramref name="obj"/> is equal to the current instance.
        /// </summary>
        /// 
        /// <param name="obj">
        /// The <see langword="object"/> to compare with the current instance.
        /// </param>
        /// 
        /// <returns>
        /// <see langword="true"/> if the specified <paramref name="obj"/> is equal to the current instance;
        /// otherwise, <see langword="false"/>.  
        /// </returns>
        /// 
        /// <remarks>None</remarks>
        [SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
        public override bool Equals(object obj)
        {
            bool result = false;

            if (!Object.Equals(obj, null))
            {
                if (obj.GetType() != typeof(CharacterLocation))
                {
                    result = false;
                }
                else
                {
                    CharacterLocation value = (CharacterLocation)obj;
                    result = ((this.Button == value.Button) && (this.Position == value.Position));
                }
            }

            return result;
        }
        #endregion

        #region public override int GetHashCode()
        /// <summary>Returns the hash code of this instance.</summary>
        /// 
        /// <returns>A 32-bit signed integer hash code.</returns>
        /// 
        /// <remarks>None</remarks>
        public override int GetHashCode()
        {
            return ToString().GetHashCode();
        }
        #endregion

        #region public override string ToString()
        /// <summary>
        /// Returns a <see langword="string"/> that represents the current instance.
        /// </summary>
        /// 
        /// <returns>
        /// A <see langword="string"/> that represents the current instance.
        /// </returns>
        /// 
        /// <remarks>None</remarks>
        public override string ToString()
        {
            return String.Format(CultureInfo.InvariantCulture, "{0},{1}", _button, _position);
        }
        #endregion
    }
}